import pygame
import sys
# 引入pygame与定义的全局变量
from pygame.locals import *
# 用来实现在控制台输出错误信息
import traceback
# 引入随机模块让小球随机生成
from random import *

# 导入自定功能类模块
import ball_module
import glass

# 初始化pygame
pygame.init()
# 初始化声音播放模块
# pygame.mixer.init()

# 预定义图片路径
bg_image = "./images/background.png"


# 设置窗口大小
bg_size = width, height = 1024, 681
screen = pygame.display.set_mode(bg_size)
# 设置窗口标题
pygame.display.set_caption("Play the ball")


def main():
    # 加载背景图
    background = pygame.image.load(bg_image)

    # 加载背景音乐
    pygame.mixer.music.load("./music/bg_music.ogg")
    pygame.mixer.music.set_volume(0.2)
    pygame.mixer.music.play()

    # 加载音效
    cat_sound = pygame.mixer.Sound("./music/cat.wav")
    dog_sound = pygame.mixer.Sound("./music/dog.wav")
    hole_sound = pygame.mixer.Sound("./music/hole.wav")
    laugh_sound = pygame.mixer.Sound("./music/laugh.wav")
    loser_sound = pygame.mixer.Sound("./music/loser.wav")
    winner_sound = pygame.mixer.Sound("./music/winner.wav")

    # 当背景音乐结束时游戏挑战失败
    GAMEOVER = USEREVENT
    pygame.mixer.music.set_endevent(GAMEOVER)

    # 生成小球
    balls = []
    BALL_NUM = 5
    # 碰撞检测组
    group = pygame.sprite.Group()

    for i in range(BALL_NUM):
        # 随机生成小球位置
        position = randint(0, width - 100), randint(0, height - 100)
        speed = [randint(1, 10), randint(1, 10)]
        # 生成小球
        ball = ball_module.Ball(speed, position, bg_size, 5 * (i+1))
        # 检测诞生的球是否会卡住其它的球
        while pygame.sprite.spritecollide(ball, group, False, pygame.sprite.collide_circle):
            ball.rect.left, ball.rect.top = randint(
                0, width - 100), randint(0, height - 100)
        balls.append(ball)
        group.add(ball)
    # 生成class类
    glassObj = glass.Glass(bg_size)

    # 记录鼠标每秒的移动次数
    motion = 0
    # 一秒检查一次鼠标移动次数
    MYTIMER = USEREVENT + 1
    pygame.time.set_timer(MYTIMER, 1000)

    # 让键盘长按响应
    pygame.key.set_repeat(100, 100)

    # 设置黑洞的位置
    hole = [(117, 119, 199, 201), (225, 227, 390, 392),
            (503, 505, 320, 322), (698, 700, 192, 194),
            (906, 908, 419, 421)]

    # 用来结束游戏
    running = True
    msgs = []
    # 定义设置帧率对象
    clock = pygame.time.Clock()
    while running:
        for event in pygame.event.get():
            # 退出游戏
            if event.type == QUIT:
                pygame.quit()
                sys.exit()

            # 结束游戏
            elif event.type == GAMEOVER:
                loser_sound.play()
                pygame.time.delay(2000)
                laugh_sound.play()
                pygame.time.delay(2000)
                running = False

            # 检查鼠标移动速度是否与小球移动速度匹配
            elif event.type == MYTIMER:
                for each in group:
                    if each.check(motion):
                        each.control = True
                        # 停止移动
                        each.speed = [0, 0]
                motion = 0

            # 检测每秒鼠标移动的次数并记录
            elif event.type == MOUSEMOTION:
                motion += 1

            # 控制小球移动
            elif event.type == KEYDOWN:
                # 按下空格判断是否进洞
                if event.key == K_SPACE:
                    for each in group:
                        for i in hole:
                            if i[0] <= each.rect.left <= i[1] and i[2] <= each.rect.top <= i[3]:
                                # 播放进洞音效
                                hole_sound.play()
                                each.speed = [0, 0]
                                # 移除黑洞位置
                                hole.remove(i)
                                # 移除碰撞检测列表
                                group.remove(each)
                                # 放在开始位置绘制
                                balls.remove(each)
                                balls.insert(0, each)
                        # 全部进洞播放结束音乐，结束游戏
                        if not hole:
                            winner_sound.play()
                            pygame.time.delay(3000)
                            msg = pygame.image.load(
                                "./images/win.png").convert_alpha()
                            msg_pos = msg.get_rect()
                            msg_pos.center = width / 2, height / 2
                            msgs.append((msg, msg_pos))
                            laugh_sound.play()

                if event.key == K_w:
                    for each in group:
                        if each.control:
                            each.speed[1] -= 1
                if event.key == K_a:
                    for each in group:
                        if each.control:
                            each.speed[0] -= 1
                if event.key == K_d:
                    for each in group:
                        if each.control:
                            each.speed[0] += 1
                if event.key == K_s:
                    for each in group:
                        if each.control:
                            each.speed[1] += 1

        # 绘制背景
        screen.blit(background, (0, 0))

        # 绘制操作窗
        screen.blit(glassObj.image, glassObj.rect)
        # 绘制在窗口移动的小鼠标图片
        # 控制移动图片
        glassObj.mouse_rect.left, glassObj.mouse_rect.top = pygame.mouse.get_pos()
        # 边界检查移动范围不能超过窗口背景
        if glassObj.mouse_rect.left < glassObj.rect.left:
            glassObj.mouse_rect.left = glassObj.rect.left
        if glassObj.mouse_rect.right > glassObj.rect.right:
            glassObj.mouse_rect.right = glassObj.rect.right
        if glassObj.mouse_rect.top < glassObj.rect.top:
            glassObj.mouse_rect.top = glassObj.rect.top
        if glassObj.mouse_rect.bottom > glassObj.rect.bottom:
            glassObj.mouse_rect.bottom = glassObj.rect.bottom
        screen.blit(glassObj.mouse_image, glassObj.mouse_rect)

        # 绘制小球
        for each in balls:
            # 小球移动
            each.move()
            if each.collide:
                each.speed = [randint(1, 10), randint(1, 10)]
                each.collide = False
            if each.control:
                screen.blit(each.green_image, each.rect)
            else:
                screen.blit(each.image, each.rect)
          # 绘制结束后图片
        if msgs:
            screen.blit(msg, msg_pos)
            pygame.time.delay(2500)

        # 碰撞检测
        for each in group:
            group.remove(each)
            # 判断是否发生碰撞
            if pygame.sprite.spritecollide(each, group, False, pygame.sprite.collide_circle):
                # 发生碰撞反方向移动
                each.side[0] = -each.side[0]
                each.side[1] = -each.side[1]
                # 玩家控制的小球反向移出碰撞范围并并从新获得随机速度
                if each.control:
                    each.side[0] = -1
                    each.side[1] = -1
                    each.control = False
                # 判断是否有发生碰撞
                each.collide = True

            group.add(each)

        pygame.display.flip()
        # 帧率为30
        clock.tick(30)


if __name__ == "__main__":
    try:
        main()
    # 正常退出就忽略
    except SystemExit:
        pass
    except:
        traceback.print_exc()
        pygame.quit()
        # 让错误停留在控制台不会一闪而果
        input()
